// Copyright (c) 2022 Presto Labs Pte. Ltd.
// Author: hyuan

#pragma once

#include <boost/foreach.hpp>

#include "coin2/exchange/base/api_util/api_signature.h"
#include "coin2/exchange/base/api_util/json_writer.h"

class MercadoSpotBaseAuth {
 public:
  virtual ~MercadoSpotBaseAuth() = default;
};


class MercadoSpotRestAuth : public MercadoSpotBaseAuth, public BaseRestAuth {
 public:
  explicit MercadoSpotRestAuth(
      const std::string& key_filepath,
      const std::string& host,
      const std::string& port,
      const std::string& bind_ip)
      : key_(AuthKey::FromFile(key_filepath)), host_(host), port_(port), bind_ip_(bind_ip) {
    header_.push_back(std::make_pair("Content-Type", "application/json"));
  }

    explicit MercadoSpotRestAuth(
      const std::string& key_filepath,
      const std::string& host,
      int32_t port,
      const std::string& bind_ip)
      : key_(AuthKey::FromFile(key_filepath)), host_(host), port_(std::to_string(port)),
          bind_ip_(bind_ip) {
    header_.push_back(std::make_pair("Content-Type", "application/json"));
  }


  AsioHttpContext* CreateRequestByGetWithSignature(
      const std::string& url_path,
      UrlParamsBuilder* builder) override {
    std::vector<std::pair<std::string, std::string>> header = header_;
    header.push_back(std::make_pair("Authorization", token_));
    std::string query_string = builder->ComputeQueryString();
    std::string target = url_path;
    if (!query_string.empty()) {
      target += "?" + query_string;
    }

    return AsioHttpContext::NewGet(host_, port_, bind_ip_, target, header);
  }

  AsioHttpContext* CreateRequestByPostWithSignature(
      const std::string& url_path,
      UrlParamsBuilder* builder) override {
    std::vector<std::pair<std::string, std::string>> header = header_;
    header.push_back(std::make_pair("Authorization", token_));
    
    std::string query_string = builder->ComputeQueryString();
    std::string post_body = builder->ComputePostBody();
    std::string target = url_path;
    if (!query_string.empty()) {
      target += "?" + query_string;
    }

    return AsioHttpContext::NewPost(host_, port_, bind_ip_, target, header, post_body);
  }

  AsioHttpContext* CreateRequestByDeleteWithSignature(
      const std::string& url_path,
      UrlParamsBuilder* builder) override {
    std::vector<std::pair<std::string, std::string>> header = header_;
    header.push_back(std::make_pair("Authorization", token_));
    
    std::string query_string = builder->ComputeQueryString();
    std::string post_body = builder->ComputePostBody();
    std::string target = url_path;
    if (!query_string.empty()) {
      target += "?" + query_string;
    }

    return AsioHttpContext::NewDelete(host_, port_, bind_ip_, target, header, post_body);
  }

  AsioHttpContext* CreateRequestByPutWithSignature(
      const std::string& address,
      UrlParamsBuilder* builder) override {
    return nullptr;
  }

  AsioHttpContext* TokenGenerator(const std::string& address){
     UrlParamsBuilder builder;
     builder.PutPost("login", key_.access_key());
     builder.PutPost("password", key_.secret_key());
     std::string post_body = builder.ComputePostBody();

    return AsioHttpContext::NewPost(host_, port_, bind_ip_, address, header_, post_body);
  }

  void SetToken(std::string token){
    token_ = std::move(token);
  }

 protected:
  AuthKey key_;
  std::string host_;
  std::string port_;
  std::string bind_ip_;
  std::string token_;
  std::vector<std::pair<std::string, std::string>> header_;

 private:

};
